#pragma once

#include "Vector2D.h"
#include "Transform.h"

// forward class declarations
class Line;
class Rect;
class Circ;
class Poly;

class Shape {
private:
	Transform* parent; // position
	Transform* offset; // offset to apply to the collider in relation to the parent Transform

	bool hasCreatedParent; // Wether this class has created an instance of Transform or not for the parent
	
	/*
	Clean up the offset.
	*/
	void CleanUpOffset();
	/*
	Clean up the parent if appropriate.
	*/
	void CleanUpParent();

protected:
	/*
	Default constructor, avoid using this.
	*/
	Shape();

public:
	/*
	Create a Shape that follows the given Transform.
	@param	position	Transform to follow.
	*/
	Shape(Transform* const position);
	/*
	Create a Shape that follows the given Transform at a given offset.
	@param	position	Transform to follow.
	@param	offset		Offset to apply to the Transform being followed.
	*/
	Shape(Transform* const position, const Vector2D& offset);
	/*
	Create a Shape that follows the given Transform at a given offset.
	@param	position	Transform to follow.
	@param	xOffset		Offset in x to apply to the Transform being followed.
	@param	yOffset		Offset in y to apply to the Transform being followed.
	*/
	Shape(Transform* const position, float xOffset, float yOffset);
	/*
	Destructor.
	*/
	virtual ~Shape();

	/*
	@return	Transform being follow by the Shape.
	*/
	Transform* GetParent() const {
		return parent;
	}
	/*
	Get the position of the Shape.
	@param	out			Vector to store the data in.
	*/
	void GetPosition(Vector2D* out) const {
		if (out != 0) {
			parent->GetPosition(out);
			out->Add(offset->GetX(), offset->GetY());
		}
		return;
	}
	/*
	@return	Position of the Shape in x.
	*/
	float GetX() const {
		return parent->GetX() + offset->GetX();
	}
	/*
	@return	Position of the Shape in y.
	*/
	float GetY() const {
		return parent->GetY() + offset->GetY();
	}
	
	/*
	Set a new parent position, to follow that one.
	@param	position		New Transform to follow.
	*/
	void SetParentPosition(Transform* const position) {
		CleanUpParent();
		parent = position;
		return;
	}
	/*
	Set a new parent position, to follow that one.
	@param	position		New Transform to follow.
	*/
	void Follow(Transform* const position) {
		SetParentPosition(position);
		return;
	}
	/*
	Set the offset of the Shape to its parent's Transform.
	@param	xOffset		Offset in x.
	*/
	void SetOffsetX(float xOffset) {
		if (offset != 0) {
			offset->SetPositionX(xOffset);
		} else {
			offset = new Transform(xOffset, 0.f);
		}
		return;
	}
	/*
	Set the offset of the Shape to its parent's Transform.
	@param	yOffset		Offset in y.
	*/
	void SetOffsetY(float yOffset) {
		if (offset != 0) {
			offset->SetPositionY(yOffset);
		} else {
			offset = new Transform(0.f, yOffset);
		}
		return;
	}
	/*
	Set the offset of the Shape to its parent's Transform.
	@param	xOffset		Offset in x.
	@param	yOffset		Offset in y.
	*/
	void SetOffset(float xOffset, float yOffset) {
		SetOffsetX(xOffset);
		SetOffsetY(yOffset);
		return;
	}
	/*
	Set the offset of the Shape to its parent's Transform.
	@param	offset		Offset.
	*/
	void SetOffset(const Vector2D& offset) {
		SetOffset(offset.x, offset.y);
	}

	/*
	Check wether or not the Shape is properly initialized and has proper parameters to use it.
	*/
	bool IsNullShape() {
		return (parent == 0) || (offset == 0);
	}

	//////////////////////////
	// Pure virtual methods //
	//////////////////////////
	virtual bool Contains(float x, float y) const = 0;
	virtual bool Contains(const Vector2D& p) const = 0;
	virtual bool CollidesWith(const Line* const l, Vector2D& hitOut) const = 0;
	virtual bool CollidesWith(const Rect* const r, Vector2D& hitOut) const = 0;
	virtual bool CollidesWith(const Circ* const c, Vector2D& hitOut) const = 0;
	virtual bool CollidesWith(const Poly* const p, Vector2D& hitOut) const = 0;

	///////////////////////
	// Debugging methods //
	///////////////////////
	virtual void Draw() const = 0;
	virtual void COut() const = 0;
};

